#ifndef SYMTAB_H_
#define SYMTAB_H_

/*

Our symbol table needs are modest.  A symbol is either a terminal or a 
non-terminal.  We only add items to the symbol table, never remove them.
                                                                
*/

#ifndef COMMON_H_
#   include "common.h"
#endif
#ifndef INPUT_H_
#   include "input.h"
#endif

enum
    {
    SYM_TERMINAL                = 0x0001,
    SYM_LEFTRECURSIVE           = 0x0002,
    SYM_FIRSTFOLLOWCLASH        = 0x0004,
    SYM_NULLABLE                = 0x0008,
    SYM_USEDINRULE              = 0x0010,
    SYM_SIMPLE                  = 0x0020,   /* symbol derives only terminals    */
    SYM_EMPTY                   = 0x0040,   /* symbol derives nothing           */
    };

struct  TRule;
struct  TOperator;
struct  TStates;

typedef struct      SYMBOLS_
    {
    void*           Dummy_;
    }               SYMBOLS_, *SYMBOLS;

typedef struct      TAction
    {
    int             Number;         /* numbered from 0..n       */
    TToken          Action;         /* contains action text     */
    int             ArgCount;       /* how many symbols to left of this action? */
    }               TAction;

typedef struct      TSymAtom        /* TSymAtom: the position-invariant aspects of a symbol */
    {
    TToken          Name;
    SYMBOLS         Definitions;
    int             BitFlags;
    }               TSymAtom;

typedef struct      TSymbol         /* An instance of a symbol          */
    {
    TToken          Name;
    TToken          Lhs;
    int             Bits;
//    int             Type;           /* TERMINAL or NONTERM                  */
    int             Value;          /* unique integer value/ID              */
    int             LeftRecursive;  /* is this nonterminal left-recursive?  */
    int             PredicateEnd;   /* end of implicit syntactic predicate? */
    int             OperatorTrigger;
    int             FirstFollowClash;
    struct TStates* LR0;
    int             Nullable;       /* symbol can derive epsilon    */
    int             Operand;
    int             UsedInRule;
    SYMBOLS         OpAbbrev;       /* list of opsyms, if this is operator abbreviation */
//    TSymbol*        LeftRecursive;  /* points to generated symbol after rewrite */
    TAction*        Action;         /* NULL unless symbol is really an action   */
    SYMBOLS         InputTokens;
    int*            LLTable;
    SYMBOLS         First;
    SYMBOLS         Follow;
    SYMBOLS         EndsWith;
    struct TRule**  Rules;
    struct TRule**  OrigRules;      /* keep original rules when transforming grammar */
    int             SelectOffset;
    }               TSymbol;

typedef struct      SymIt   /* symbol list iterator */
    {
    SYMBOLS         List;        
    TSymbol*        Symbol;
    int             Count;
    int             Index;
    }               SymIt;

SymIt       SymItNew(SYMBOLS List);
int         SymbolIterate(SymIt* Info);


enum ItemType  { TERMINAL, NONTERM };

enum OperatorType { OP_UNKNOWN, OP_BINARY, OP_PRE_UNARY, OP_POST_UNARY, OP_TRINARY };

void    SymbolInit(void);
void    SymbolFini(void);

int     PatternCmp(const char* Pattern, const char* OpStr);

enum OPSYMFLAGS
    {
    OPFL_LEFT_BRACKET       = 0x0001,
    OPFL_RIGHT_BRACKET      = 0x0002,
    };


typedef struct      TOperator
    {
    TToken          Decl;
    int             IntRep;
    int             Precedence;
    int             Associativity;
    int             Used;           /* true if operator used in a production */
    const char*     Pattern;
    int             SymCount;
    SYMBOLS         List;
    int             Flags;
    }               TOperator;

typedef struct      TRule
    {
    int             RuleId;         /* rules are numbered from 0..n         */
    int             Nullable;       /* rule can derive epsilon              */
    int             Predicate;      /* rule has predicate                   */
    SYMBOLS         Symbols;        /* Symbols this rule produces (rhs)     */
    TToken*         Tokens;         /* for positional info                  */
    int*            InLoop;         /* TRUE if part of left recursive loop  */
    SYMBOLS         First;
    TOperator*      Operator;
    int             ProductionOffset;
    int             LeftFactor;     /* used during left factoring           */
    struct TRule*   LeftRecursive;  /* if this is rewrite, points to original rule */
    int             TailRecursive;  /* TRUE if right-recursive grammar rewrite  */
    }               TRule;


typedef struct      RuleIt   /* Rule iterator */
    {
    TSymbol*        Root;
    int             NRules;
    TRule*          Rule;
    int             iRule;
    int             NProdItems;
    TSymbol*        ProdItem;
    int             iProdItem;
    int             Finished;   /* TRUE while iRule < NRules */
    }               RuleIt;

RuleIt  RuleItNew(TSymbol* Root);
void    RuleItNext(RuleIt* Info);
int     RuleIterate(RuleIt* Info);

void    RuleFree(TRule* Rule);
int     RuleCount(TSymbol* Symbol);

int     RuleItemCount(TRule* Rule);
SYMBOLS RuleFirst(TSymbol* NonTerm, TRule* Rule, int iProdItem);
int     RuleNullable(TRule* Rule, int iProdItem);
int     RuleIsNull(TRule* Rule);
TRule*  RuleDup(TRule* Rule);

void    RuleAddSymbol(TRule* Rule, TSymbol* Symbol, TToken Token);
TSymbol*    RuleRemoveSymbol(TRule* Rule, int Pos);


int         SymbolIsEqual(TSymbol* A, TSymbol* B);
int         SymbolIsNullable(TSymbol* A);
int         SymbolSetBit(TSymbol* Symbol, int Bit);
int         SymbolGetBit(TSymbol* Symbol, int Bit);
TSymbol*    SymbolFind(TToken Token);
TSymbol*    SymbolFromValue(int Value);
TSymbol*    SymbolSetValue(TSymbol* Symbol, int Value);
TSymbol*    SymbolAdd(TToken Token, int Type);
TSymbol*    SymbolStart(void);
int         SymbolIsAction(TSymbol* Symbol);
int         SymbolIsEmpty(TSymbol* Symbol);
int         SymbolIsTerminal(TSymbol* Symbol);
int         SymbolIsOpSyms(TSymbol* Symbol);
SYMBOLS     SymbolGetAllSymbols(TSymbol* Symbol);

TSymbol*    SymbolAddStart(TSymbol* StartSymbol);
const char* SymbolStr(TSymbol* Symbol);

TRule*      SymbolNewRule(TSymbol* Symbol);
TRule*      SymbolAddRule(TSymbol* Symbol, TRule* Rule);
TRule*      SymbolDupRule(TSymbol* Symbol, TRule* OldRule);

SYMBOLS     SymbolListCreate(void);
//#ifdef MEMWATCH
//#   define  SymbolListCreate() (SYMBOLS)mwMark((void*)SymbolListCreate(), "symbol list", __FILE__, __LINE__)
//#endif
SYMBOLS     SymbolListDestroy(SYMBOLS List);
//#ifdef MEMWATCH
//#   define  SymbolListDestroy(List) ((List)?(mwUnmark(List, __FILE__, __LINE__),SymbolListDestroy(List)):NULL)
//#endif
SYMBOLS     SymbolListAdd(SYMBOLS List, TSymbol* Symbol);
//#ifdef MEMWATCH
#if 0
#   define  SymbolListAdd(List, Symbol) List?SymbolListAdd(List,Symbol):(SYMBOLS)mwMark(SymbolListAdd(List,Symbol), "SymbolListAdd", __FILE__, __LINE__);
#endif
SYMBOLS     SymbolListAddFirst(SYMBOLS List, TSymbol* ProdItem);
int         SymbolListAddList(SYMBOLS* List, SYMBOLS Add);
SYMBOLS     SymbolListAddUnique(SYMBOLS Handle, TSymbol* Symbol);
SYMBOLS     SymbolListCopy(SYMBOLS To, SYMBOLS From);
TSymbol*    SymbolListGet(SYMBOLS List, int Index);
int         SymbolListEqual(SYMBOLS A, SYMBOLS B);
TSymbol*    SymbolListFind(SYMBOLS List, TToken Token);
int         SymbolListCount(SYMBOLS List);
int         SymbolListCountSig(SYMBOLS List);
int         SymbolListIndex(SYMBOLS List, TSymbol* Symbol);
int         SymbolListRemove(SYMBOLS List, TSymbol* Symbol);
SYMBOLS     SymbolListTruncate(SYMBOLS List, int NewLen);
TSymbol*    SymbolListDelete(SYMBOLS List, int Position);
int         SymbolListContains(SYMBOLS List, TSymbol* Symbol);
SYMBOLS     SymbolListIntersect(SYMBOLS List, SYMBOLS With);
int         SymbolListDump(FILE* Handle, SYMBOLS List, const char* Sep);
char*       SymbolListDumpStr(SYMBOLS List, const char* Sep);
#define     SymbolListPush SymbolListAdd
/* void        SymbolListPush(SYMBOLS List, TSymbol* Symbol);*/
TSymbol*    SymbolListPop(SYMBOLS List);
TSymbol*    SymbolListTop(SYMBOLS List);
SYMBOLS     SymbolListReplace(SYMBOLS List, int Pos, SYMBOLS Insert);

TToken      Unquote(TToken Token);

TSymbol*    LiteralFind(TToken Token);
void        LiteralAdd(TSymbol* Symbol, TToken Token);
TToken      LiteralFromSymbol(TSymbol* Symbol);

extern  TSymbol*    EndSymbol;
extern  TSymbol*    EolSymbol;
extern  TSymbol*    MatchAnySymbol;
extern  TSymbol*    NoActionSymbol;


TSymbol*    SymbolNewNonTerm(TToken Token);
TSymbol*    SymbolNewTerm(TToken Token);

void    DumpTreeSymbol(TSymbol* Symbol, int Annotate);


#endif  /* SYMTAB_H_ */
